<?php
class Exams extends Controller {
	
	var $name = 'exams';
	
	private $maxQuestions = 10;
	
	/**
	 * 
	 * Monta a tela de questões
	 */
	public function index_action() {

		//id da unidade
		$unitid = $this->getParam('unit');	
		$userid = $this->USER->id;	
		$data['unitid'] = $unitid;
		try {
			//Faz a consulta no banco de dados e recupera a unidade
			$unit = $this->DB->get_records('oaeditor_units', array('id'=>$unitid));
			$nameUnit =  $unit[$unitid]->name;
			
			$this->bar_title = 'Questões da unidade :: '.$nameUnit;
			
			if(empty($unit)) {
				throw new Exception("Erro ao tentar recuperar a unidade do banco de dados.");				
			}

			if($_POST) {
				$controle = true;
				//verifica se todos os campos estão preenchidos
				foreach($_POST as $value) {
					if($value == '' || $value == 'null') {
						$controle = false;
						break;
					}
				}
				
				if($controle) {
					//Recebe a nota e as questões com o status de certo ou errado					
					$result = $this->result($_POST);
					//Salva o exame no banco de dados
					$examid = $this->saveExam($unitid, $result['note']);
					//Salva as questões no banco de dados					
					$this->saveQuestionsResolved($examid, $result['answers'], $result['marked']);	
					//Nota
					$data['note'] = $result['note'];
					//questões escolhidas				
					$data['questions'] = $this->mergeArrays($result['questions'], $_POST);
					//Manda para a view as questões
					$this->view('answers', $data);
				}else {
					var_dump('Alguma questão não foi preenchida.');
				}				
			}else {						
				$conditions = array('userid'=>$userid, 'unitid'=>$unitid);
				$hasExam = $this->DB->get_record('oaeditor_exams', $conditions);				
				$allConcepts = $this->getAllConcepts($nameUnit);
						
				if(!$hasExam) {						
					$conceptsVisited = $this->getConceptsVisited($unitid, $userid);
					$conceptsNotVisited = $this->getConceptsNotVisited($allConcepts, $conceptsVisited);
					
					$data['nameUnit'] = $nameUnit;
					$data['questionsConceptsVisited'] = $this->getQuestionsForConcepts($allConcepts, $conceptsVisited, $unitid);
					$data['questionsConceptsNotVisited'] = $this->getQuestionsForConcepts($allConcepts, $conceptsNotVisited, $unitid);
					
					$data['questions'] = array_merge($data['questionsConceptsVisited'], $data['questionsConceptsNotVisited']);
				}else {
					//Pega o ultimo exame
					$lastExam = $this->lastExam($unitid, $userid);
					//Pega os conceitos que foram mais errados							
					$questions = $this->getQuestionsAfterExam($unitid, $lastExam[$unitid]->id, $allConcepts);
					
					$data['questions'] = $questions;
				}	
				
				$this->view('index', $data);
			}				
		}catch(Exception $ex) {
			$this->setErro($ex->getMessage());
			//header('Location: '.WWW_APP.'units/');
		}		
		
	}
	
	/**
	 * 
	 * Método específico que junta as repostas respondidas com o array de questões
	 * @param array $array1	array de questões
	 * @param array $array2 array com as respostas do post
	 */
	private function mergeArrays($array1, $array2) {
		
		$i = 0;
		foreach($array2 as $value) {			
			$array1[$i]->answered = $value;
			$i++;			
		}
		
		return $array1;
	}
	
	/**
	 * 
	 * Pega o último exame do aluno
	 * @param int $unitid   id da unidade
	 * @param int $userid   id do usuário
	 */
	private function lastExam($unitid, $userid) {		
		
		$sql = "SELECT unitid, userid, id, note, MAX(`date`) as date 
				FROM `oaeditor_exams` WHERE `unitid`=? AND `userid`=?";
		$params = array('unitid'=>$unitid, 'userid'=>$userid);
		
		$lastExam = $this->DB->get_records_sql($sql, $params);

		return $lastExam;		
	}
	
	/**
	 * 
	 * retorna array de conceitos errados
	 * @param id $examid  id do exame
	 */
	private function getConceptsWrong($examid) {
		
		$conceptsWrong = array();		
		$conditions = array('examid'=>$examid);
		$answers = $this->DB->get_records('oaeditor_questions_resolved', $conditions, false);
		
		foreach($answers as $answer) {
			$question = $this->DB->get_record('oaeditor_questions', array('id'=>$answer->questionid));
			if($answer->hit == 0) {				
				$conceptsWrong[] = $question->related_concept;
			}			
		}
		
		$conceptsWrong = array_unique($conceptsWrong);
		
		return $conceptsWrong;
	}
	
	/**
	 * 
	 * Retorna array de conceitos não errados
	 * @param array $allConcepts   array com todos os conceitos
	 * @param array $conceptsWrong array com o conceitos errados
	 */
	public function getConceptsNotWrong($allConcepts, $conceptsWrong) {
		
		foreach($allConcepts as $key=>$value) {
			$all[] = $key;
		}
		
		$diff = array_diff($all, $conceptsWrong);	
		
		if(empty($diff)) {
			$diff = array();
		}
		
		return $diff;
	}
	
	/**
	 * 
	 * Retorna as questões depois de feito o exame pelo menos uma vez
	 * @param int $unitid         id da unidade
	 * @param int $examid		  id do exame
	 * @param array $allConcepts  array com todos os conceitos
	 */
	private function getQuestionsAfterExam($unitid, $examid, $allConcepts) {
		
		$conceptsWrong = $this->getConceptsWrong($examid);
		$conceptsNotWrong = $this->getConceptsNotWrong($allConcepts, $conceptsWrong);
		
		$questionsConceptsWrong = $this->getQuestionsForConcepts($allConcepts, $conceptsWrong, $unitid);
		$questionsConceptsNotWrong = $this->getQuestionsForConcepts($allConcepts, $conceptsNotWrong, $unitid);

		$questions = array_merge($questionsConceptsWrong, $questionsConceptsNotWrong);
				
		return $questions;		
	}
	
	/**
	 * 
	 * Salva o exame no banco de dados e retorna o seu id
	 * @param int $unitid  id da unidade
	 * @param int $note	   nota do aluno
	 */
	private function saveExam($unitid, $note) {
		//Monta o registro pra salvar no banco de dados
		$record = new stdClass();
		$record->userid = $this->USER->id;
		$record->unitid = $unitid;
		$record->note = $note;
		$record->date = date('Y-m-d H:m:s');
		//Salva o registro e pega seu id
		$lastid = $this->DB->insert_record('oaeditor_exams', $record);
		
		return $lastid;
	}
	
	/**
	 * 
	 * Salva as questões na tabela de questões resolvidas
	 * @param int 	$examid  id do exame no banco de dados
	 * @param array $answers respostas com o status de certo ou errado
	 */
	private function saveQuestionsResolved($examid, $answers, $marked) {
		
		//Salva todas as questões no banco
		foreach($answers as $key=>$answer) {
			
			//Monta o registro pra salvar no banco de dados
			$record = new stdClass();
			$record->questionid = $key;
			$record->examid = $examid;
			$record->hit = $answer;		
			$record->marked = $marked[$key];	
			//insere o registro no banco de dados
			$this->DB->insert_record('oaeditor_questions_resolved', $record, false);				
		}
	}
	
	/**
	 * 
	 * Método que retorna um array de conceitos da unidade passada como parâmetro
	 * @param String $name_unit   nome da unidade
	 */
	private function getAllConcepts($name_unit) {
		
		//Lê o xml da unidade
		$xml = simplexml_load_file(FILES.$name_unit.DS."graph.xml");
		
		if(!$xml) {
			return false;
		}
		$nodes[0] = "Introdução";
		//Monta o array de conceitos
		foreach($xml->node as $node) {
    		$nodes[(String)$node['id']] = (String)$node['name'];			
    	}
    	
    	//retorna o array de conceitos
   		return $nodes;
   				
	}
	
	/**
	 * 
	 * Retorna um array com os conceitos visitados
	 * @param int $unitid  id da unidade no banco de dados
	 */
	private function getConceptsVisited($unitid, $userid) {
		
		$sql = "SELECT DISTINCT conceptid, id FROM `oaeditor_logs` WHERE `unitid`=? and `userid`=?";
		$params = array('unitid'=>$unitid, 'userid'=>$userid);
		
		$conceptsVisited = $this->DB->get_records_sql($sql, $params);
		
		foreach ($conceptsVisited as $value) {			
			$visited[$value->id] = $value->conceptid;			
		}
		
		if($visited == null) {
			$visited = array();
		}
		
		return $visited;
		
	}
	
	/**
	 * 
	 * Retorna um array com os conceitos não visitados
	 * @param array array contendo todos os conceitos
	 * @param array array contendo apenas os conceitos visitados
	 */
	private function getConceptsNotVisited($allConcepts, $conceptsVisited) {
		$all = array();
		$visited = array();
		
		//Monta array de todos os conceitos
		foreach($allConcepts as $key=>$value) {
			$all[] = $key;
		}
		//Monta array dos conceitos visitados
		foreach($conceptsVisited as $key=>$value) {
			$visited[] = $value;
		}
		//Verifica os arrays que não foram visitados
		$nonVisited = array_diff($all, $visited);
		
		return $nonVisited;
	}
	
	/**
	 * 
	 * Retorna a quantidade de questões que deve ser gerada
	 * @param int total de todos os conceitos
	 * @param int total dos conceitos visitados ou não visitados
	 */
	private function getAmountQuestionForConcepts($sumAllConcepts, $sumConcepts) {
		
		$percent = $sumConcepts / $sumAllConcepts;
		
		$sum = $percent * $this->maxQuestions;		
		
		return round($sum);
	}
		
	/**
	 * 
	 * Retorna um array com a quantidade correta de questões dos conceitos 
	 * visitados ou não visitados(depende do parâmetro $concepts)
	 * 
	 * @param array $allConcepts		array de todos os conceitos	
	 * @param array $concepts			array dos conceitos visitados ou não visitados
	 * @param int 	$unitid				id da unidade no banco de dados
	 */
	private function getQuestionsForConcepts($allConcepts, $concepts, $unitid) {

		if(empty($concepts)) {
			return array();
		}
		
		//Total de conceitos da unidade
		$sumAllConcepts = count($allConcepts);
		//total de conceitos
		$sumConcepts = count($concepts);
		//quantidade de questões que deve ser gerada dos conceitos 
		$amount = $this->getAmountQuestionForConcepts($sumAllConcepts, $sumConcepts);
		//Pega todas as questões relacionadas com os conceitos 
		$allQuestions = $this->getQuestionsRelatedConcepts($unitid, $concepts);
		
		//Se a quantidade de questões é menor que a quantidade total, retorna todas as questões
		if(count($allQuestions) <= $amount) {			
			$questions = $allQuestions;			
		}else {			
			for($i = 0; $i < $amount; $i++) {
				//valor máximo para realizar um random
				$max = count($allQuestions) - 1;
				//Questão selecionada aleatoriamente
				$questionSelected = rand(0, $max);
				//Adiciona a quesão ao array de questões
				$questions[] = $allQuestions[$questionSelected];
				//Remove a questão selecionada para que não se repita
				unset($allQuestions[$questionSelected]);
				//reordena o array iniciando do indice 0
				$allQuestions = array_values($allQuestions);
			}			
		}	
		
		return $questions;
	}	
	
	/**
	 * 
	 * Retorna um array contendo todas as questões dos conceitos visitados ou não visitados
	 * @param int $unitid	id da unidade no banco de dados
	 * @param array $concepts array dos conceitos visitados ou não visitados
	 */
	private function getQuestionsRelatedConcepts($unitid, $concepts) {
		//Percorre todos os conceitos visitados ou não visitados(depende do parâmetro $concepts)
		foreach($concepts as $key=>$value) {
			//Faz a consulta e recebe todas as questões associadas com aquele conceito
			$question = $this->DB->get_records('oaeditor_questions', array('unitid'=>$unitid, 'related_concept'=>$value));
			
			foreach($question as $value) {
				//Vai montando um array de perguntas 
				$questions[] = $value;	
			}			
		}
		
		return $questions;
	}	
	
	/**
	 * 
	 * Retorna um array com a nota e as questões com o status de certo ou errada
	 * @param 	array 	ansers  respostas vindas do formulário
	 */
	private function result($answers) {
		
		//Itera sobre todas as questões, pegando o id dela e montando um array 
		//das respostas corretas(de acordo com o banco) e um array das respostas
		//vindas do formulário
		foreach($answers as $key=>$answer) {
			$questionid = str_replace("question_", "",$key);
			$condition = array('id'=>$questionid);
			$question = $this->DB->get_records('oaeditor_questions', $condition);
			$questions[] = $question[$questionid];
			$corrects[$questionid] = $question[$questionid]->answer_correct;
			$answered[$questionid] = $answer;
		}
		
		$nota = 0;
		foreach($answered as $key=>$value) {
			$marked[$key] = $value;
			//armazena as respostas corretas
			if($answered[$key] == $corrects[$key]) {
				$nota++;
				$return[$key] = 1;				
			}else {
				$return[$key] = 0;
			}
		}
		//nota do aluno
		$array['note'] = $nota;
		//respostas com o status de certa ou errada
		$array['answers'] = $return;
		//array com as questões
		$array['questions'] = $questions;
		//Questões respondidas
		$array['marked'] = $marked;
		
		return $array;
	}
	
}